/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.bpm.api.runtime.process;

import com.je.bpm.engine.ActivitiException;
import com.je.bpm.model.process.payloads.*;
import com.je.bpm.model.process.results.*;
import com.je.bpm.model.shared.Result;
import com.je.bpm.runtime.process.ProcessOperatorService;
import com.je.bpm.runtime.process.operator.*;
import com.je.bpm.runtime.process.payloads.*;
import com.je.bpm.runtime.shared.operator.Operator;
import com.je.bpm.runtime.shared.operator.validator.PayloadValidErrorException;

import java.util.HashMap;
import java.util.Map;

public class ProcessOperatorServiceImpl implements ProcessOperatorService {

    private Map<String, Operator> processOperator = new HashMap<>();
    private ProcessInstanceActiveOperator processActiveOperator;
    private ProcessInstanceCancelOperator processCancelOperator;
    private ProcessInstanceHangOperator processHangOperator;
    private ProcessInstanceInvalidOperator processInvalidOperator;
    private ProcessEmptyStartOperator processStartOperator;
    private ProcessEmptySponsorOperator processSponsorOperator;
    private ProcessDefinitionGetOperator getProcessDefinitionOperator;
    private ProcessModelSaveOperator processModelSaveOperator;
    private ProcessGetButtonOperator processGetButtonOperator;
    private ProcessGetNextElementOperator processGetNextElementOperator;
    private ProcessGetGobackElementOperator processGetGobackElementOperator;
    private ProcessGetDelegateElementOperator processGetDelegateElementOperator;
    private ProcessGetDismissElementOperator processGetDismissElementOperator;
    private ProcessGetCirculatedInfoOperator processGetCirculatedInfoOperator;
    private ProcessGetNextElementAssigneeOperator processGetNextElementAssigneeOperator;

    public ProcessOperatorServiceImpl(ProcessInstanceActiveOperator processActiveOperator, ProcessInstanceCancelOperator processCancelOperator,
                                      ProcessInstanceHangOperator processHangOperator, ProcessInstanceInvalidOperator processInvalidOperator,
                                      ProcessEmptyStartOperator processStartOperator, ProcessEmptySponsorOperator processSponsorOperator,
                                      ProcessDefinitionGetOperator getProcessDefinitionOperator,
                                      ProcessModelSaveOperator processModelSaveOperator,
                                      ProcessGetButtonOperator processGetButtonOperator,
                                      ProcessGetNextElementOperator processGetNextElementOperator,
                                      ProcessGetGobackElementOperator processGetGobackElementOperator,
                                      ProcessGetDelegateElementOperator processGetDelegateElementOperator,
                                      ProcessGetDismissElementOperator processGetDismissElementOperator,
                                      ProcessGetCirculatedInfoOperator processGetCirculatedInfoOperator,
                                      ProcessGetNextElementAssigneeOperator processGetNextElementAssigneeOperator) {
        this.processActiveOperator = processActiveOperator;
        this.processCancelOperator = processCancelOperator;
        this.processHangOperator = processHangOperator;
        this.processInvalidOperator = processInvalidOperator;
        this.processStartOperator = processStartOperator;
        this.processSponsorOperator = processSponsorOperator;
        this.getProcessDefinitionOperator = getProcessDefinitionOperator;
        this.processModelSaveOperator = processModelSaveOperator;
        this.processGetButtonOperator = processGetButtonOperator;
        this.processGetNextElementOperator = processGetNextElementOperator;
        this.processGetGobackElementOperator = processGetGobackElementOperator;
        this.processGetDelegateElementOperator = processGetDelegateElementOperator;
        this.processGetDismissElementOperator = processGetDismissElementOperator;
        this.processGetCirculatedInfoOperator = processGetCirculatedInfoOperator;
        this.processGetNextElementAssigneeOperator = processGetNextElementAssigneeOperator;

        processOperator.put(processActiveOperator.getId(), processActiveOperator);
        processOperator.put(processCancelOperator.getId(), processCancelOperator);
        processOperator.put(processHangOperator.getId(), processHangOperator);
        processOperator.put(processInvalidOperator.getId(), processInvalidOperator);
        processOperator.put(processStartOperator.getId(), processStartOperator);
        processOperator.put(processSponsorOperator.getId(), processSponsorOperator);
        processOperator.put(getProcessDefinitionOperator.getId(), getProcessDefinitionOperator);
        processOperator.put(processGetButtonOperator.getId(), processGetButtonOperator);
        processOperator.put(processGetNextElementOperator.getId(), processGetNextElementOperator);
        processOperator.put(processGetGobackElementOperator.getId(), processGetGobackElementOperator);
        processOperator.put(processGetDelegateElementOperator.getId(), processGetDelegateElementOperator);
        processOperator.put(processGetDismissElementOperator.getId(), processGetDismissElementOperator);
        processOperator.put(processGetCirculatedInfoOperator.getId(), processGetCirculatedInfoOperator);
        processOperator.put(processGetNextElementAssigneeOperator.getId(), processGetNextElementAssigneeOperator);
    }

    @Override
    public boolean checkOperateExits(String operatorId) {
        return processOperator.containsKey(operatorId);
    }

    @Override
    public Result operate(String operationId, Map<String, Object> params) throws PayloadValidErrorException {
        Operator operator = processOperator.get(operationId);
        if (operator == null) {
            throw new ActivitiException("Can't find the operator form the process operation!");
        }
        return operator.operate(params);
    }

    @Override
    public ProcessButtonListResult getButton(String funcCode, String userId, String beanId, Map<String, Object> bean) throws PayloadValidErrorException {
        return processGetButtonOperator.operate(ProcessGetButtonPayload.build().setFuncCode(funcCode).setUserId(userId).setBeanId(beanId).setBean(bean));
    }

    @Override
    public ProcessNextElementResult getSubmitOutGoingNode(String taskId, String pdid, String prod, Map<String, Object> bean) throws PayloadValidErrorException {
        return processGetNextElementOperator.operate(ProcessGetNextElementPayload.build().setPdid(pdid).setTaskId(taskId).setProd(prod).setBean(bean));
    }

    @Override
    public ProcessNextElementAssigneeResult getSubmitOutGoingNodeAssignee(String taskId, String pdid, String prod, String target, Map<String, Object> bean, String operationId) throws PayloadValidErrorException {
        return processGetNextElementAssigneeOperator.operate(ProcessGetNextElementAssigneePayload.build().setPdid(pdid).setTaskId(taskId).setProd(prod).setTarget(target).setBean(bean).setOperationId(operationId));
    }

    @Override
    public ProcessCirculatedElementResult getCirculatedInfo(String taskId, String prod, Map<String, Object> bean) throws PayloadValidErrorException {
        return processGetCirculatedInfoOperator.operate(ProcessGetCirculatedInfoPayload.build().setTaskId(taskId).setProd(prod).setBean(bean));
    }


    @Override
    public ProcessDismissElementResult getDismissOutGoingNode(String piid, String taskId, String pdid, Map<String, Object> bean) throws PayloadValidErrorException {
        return processGetDismissElementOperator.operate(ProcessGetDismissElementPayload.build().setPdid(pdid).setPiid(piid).setTaskId(taskId).setBean(bean));
    }

    @Override
    public ProcessGobackElementResult getGobackNodeName(String piid, String taskId) throws PayloadValidErrorException {
        return processGetGobackElementOperator.operate(ProcessGetGobackElementPayload.build().setPiid(piid).setTaskId(taskId).setType("goBack"));
    }

    @Override
    public ProcessGobackElementResult getDismissNodeName(String piid, String taskId) throws PayloadValidErrorException {
        return processGetGobackElementOperator.operate(ProcessGetGobackElementPayload.build().setPiid(piid).setTaskId(taskId).setType("dismiss"));
    }

    @Override
    public ProcessGobackElementResult getRetrieveNodeName(String piid, String taskId) throws PayloadValidErrorException {
        return processGetGobackElementOperator.operate(ProcessGetGobackElementPayload.build().setPiid(piid).setTaskId(taskId).setType("retrieve"));
    }

    @Override
    public ProcessDelegateElementResult getDelegateNode(String piid, String taskId) throws PayloadValidErrorException {
        return processGetDelegateElementOperator.operate(ProcessGetDelegateElementPayload.build().setTaskId(taskId).setPiid(piid));
    }


    @Override
    public ProcessInstanceResult start(String prod, String processDefinitionId, String beanId) throws PayloadValidErrorException {
        return processStartOperator.operate(ProcessEmptyStartPayload.build()
                .setProd(prod)
                .setProcessDefinitionId(processDefinitionId)
                .setBeanId(beanId));
    }

    @Override
    public ProcessInstanceResult sponsor(String prod, String processDefinitionKey, String beanId, String assignee) throws PayloadValidErrorException {
        return processSponsorOperator.operate(ProcessEmptySponsorPayload.build().
                setProd(prod)
                .setProcessDefinitionKey(processDefinitionKey)
                .setBeanId(beanId)
                .setAssignee(assignee));
    }


    @Override
    public ProcessInstanceResult hang(String prod, String piid, String beanId) throws PayloadValidErrorException {
        return processHangOperator.operate(ProcessInstanceHangPayload.build()
                .setProd(prod)
                .setPiid(piid)
                .setBeanId(beanId));
    }

    @Override
    public ProcessInstanceResult active(String prod, String piid, String beanId) throws PayloadValidErrorException {
        return processActiveOperator.operate(ProcessInstanceActivePayload.build()
                .setProd(prod)
                .setPiid(piid)
                .setBeanId(beanId));
    }

    @Override
    public ProcessDefinitionResult cancel(String prod, String pdid, String piid, String beanId) throws PayloadValidErrorException {
        return processCancelOperator.operate(ProcessInstanceCancelPayload.build()
                .setProd(prod)
                .setPdid(pdid)
                .setPiid(piid)
                .setBeanId(beanId));
    }

    @Override
    public ProcessDefinitionResult invalid(String prod, String pdid, String piid, String beanId) throws PayloadValidErrorException {
        return processInvalidOperator.operate(ProcessInstanceInvalidPayload.build()
                .setProd(prod)
                .setPdid(pdid)
                .setPiid(piid)
                .setBeanId(beanId));
    }

    @Override
    public ProcessDefinitionResult getProcessDefinition(String prod, String pdid, String beanId) throws PayloadValidErrorException {
        return getProcessDefinitionOperator.operate(ProcessDefinitionGetPayload.build()
                .setProd(prod)
                .setPdid(pdid)
                .setBeanId(beanId));
    }

    @Override
    public ProcessModelResult saveModel(String modelId, String modelName, String modelKey, String runModeCode, String runModeName,
                                        String category, String funcCode, String funcName, String metaInfo) throws PayloadValidErrorException {
        return processModelSaveOperator.operate(SaveOrUpdateProcessModelPayload.build()
                .setModelId(modelId)
                .setRunModeCode(runModeCode)
                .setRunModeName(runModeName)
                .setCategory(category)
                .setFuncCode(funcCode)
                .setFuncName(funcName)
                .setMetaInfo(metaInfo));
    }

}
